'use strict';

var app = angular.module('myapp', []);

app.controller('addressctrl', ['$scope', '$http', 'TreeData', function($scope, $http, TreeData) {

    function getData() {
        $http.get('data/city.json').success(function (data) {
            console.log(convert(data));
            $scope.tree = new TreeData(convert(data));
        }).error(function (res) {
            console.log(res);
        });
    }

    /**
     * 将本地地址数据转化为可用的结构
     * @param item
     * @returns {Array}
     */
    function convert(item) {
        var arr = []
        if(angular.isArray(item)) {
            angular.forEach(item, function (v) {
                arr.push({
                    label: v
                })
            })
        } else {
            angular.forEach(item, function (v, k) {
                arr.push({
                    label: k,
                    items: convert(v),
                    folded: true
                })
            })
        }
        return arr;
    }

    $scope.getCheckedChildren = function () {
        $scope.checkeds = $scope.tree.getChecked();
        console.log($scope.checkeds);
    }
    
    getData();

}]);

app.factory('TreeData', function () {
    return function (tree) {
        var me = this;
        me.$data = tree;

        /**
         * 折叠或展开文件夹
         * @param item
         * @param folded
         */
        me.toggleFold = function (item, folded) {
            item.folded = angular.isUndefined(folded) ? !item.folded : folded;
        }

        /**
         * 折叠文件夹
         * @param item
         */
        me.fold = function (item) {
            item.folded = true;
        }

        /**
         * 展开文件夹
         * @param item
         */
        me.unFold = function (item) {
            item.folded = false;
        }

        /**
         * 选中单个
         * @param item
         */
        me.check = function (item) {
            me._updateChildrenCheck(item);
            me._updateParentsCheck(me.$data);
        }

        /**
         * 更新子树的选中状态
         * @param item
         * @private
         */
        me._updateChildrenCheck = function (item) {
            if(item.items) {
                angular.forEach(item.items, function (v) {
                    v.checked = item.checked;
                    me._updateChildrenCheck(v);
                })
            }
        }

        /**
         * 根据子树状态更新父节点选中状态
         * @param items
         * @private
         */
        me._updateParentsCheck = function (items) {
            angular.forEach(items, function (d) {
                if(d.items) {
                    me._updateParentsCheck(d.items);
                    d.checked = me._hasCheckedChildren(d);
                    d.semiChecked = me._hasUncheckedChildren(d);
                }
            })
        }

        /**
         * 判断是否有选中的子树
         * @param item
         * @returns {boolean}
         * @private
         */
        me._hasCheckedChildren = function (item) {
            var result = false;
            angular.forEach(item.items, function (v) {
                result = result || v.checked;
                if(v.items && !result) {
                    result = result || me._hasCheckedChildren(v);
                }
            })
            return result;
        }

        /**
         * 判断是否有没有选中的子树
         * @param item
         * @returns {boolean}
         * @private
         */
        me._hasUncheckedChildren = function (item) {
            var result = false;
            angular.forEach(item.items, function (v) {
                result = result || !v.checked;
                if(v.items && !result) {
                    result = result || me._hasUncheckedChildren(v);
                }
            })
            return result;
        }

        /**
         * 是否半选中
         * @param item
         * @returns {boolean|*}
         */
        me.isSemiChecked = function (item) {
            return item.checked && item.semiChecked;
        }

        /**
         * 获取所有选中的数据
         */
        me.getChecked = function () {
            return me._getCheckedChildren(me.$data);
        }

        /**
         * 获取选中了的子树，不深入
         * @param items
         * @returns {Array}
         * @private
         */
        me._getCheckedChildren = function (items) {
            var arr = [];
            angular.forEach(items, function (v) {
                if(v.checked) {
                    if(!v.semiChecked) {
                        arr.push(v)
                    } else {
                        arr = arr.concat(me._getCheckedChildren(v.items));
                    }
                }
            })
            return arr;
        }

    }
})

/**
 * 原版， http://showcase.ngnice.com/#/tree/treeData
 */
app.factory('TreeData_', function() {
    /**
     * 能够自动处理树形数据联动的类，子节点列表必须命名为items。同时，节点会被增加三个属性：checked, folded, intermediate
     * @example
     * var data = new TreeData([
     *   {
   *     label: 'a',
   *     items: [
   *       {
   *         label: 'a1'
   *       },
   *       {
   *         label: 'a2'
   *       }
   *     ]
   *   },
     *   {
   *     label: 'b',
   *     items: [
   *       {
   *         label: 'b1'
   *       },
   *       {
   *         label: 'b2'
   *       }
   *     ]
   *   }
     * ]);
     * @param tree {Array.<Object>}
     * @param cbIsSame {function(Object, Object):boolean}
     * @constructor
     */
    function TreeData(tree, cbIsSame) {
        var _this = this;
        _this.tree = tree;
        _this.isSame = cbIsSame || function(item1, item2) { return item1 === item2 };
        /**
         * 折叠/展开
         * @param item {Object}
         * @param folded
         * @private
         */
        _this._fold = function(item, folded) {
            item.folded = folded;
        };
        /**
         * 折叠指定的节点
         * @param item {Object}
         */
        _this.fold = function(item) {
            _this._fold(item, true);
        };
        /**
         * 展开指定的节点
         * @param item {Object}
         */
        _this.unfold = function(item) {
            _this._fold(item, false);
        };
        /**
         * 切换节点的折叠状态
         * @param item {Object}
         */
        _this.toggleFold = function(item) {
            _this._fold(item, !item.folded);
        };
        /**
         * 检查指定节点的折叠状态
         * @param item {Object}
         * @returns {boolean}
         */
        _this.isFolded = function(item) {
            return item.folded;
        };
        /**
         * 递归检查指定节点是否有选中状态的子节点，不检查当前节点状态
         * @param item {Object} 起始节点
         * @return {boolean}
         */
        _this.hasCheckedChildren = function(item) {
            return !!_this.find(item.items, function(subItem) {
                return subItem.checked || _this.hasCheckedChildren(subItem);
            });
        };
        /**
         * 递归检查指定节点是否有未选中状态的子节点，不检查当前节点状态
         * @param item {Object} 起始节点
         * @return {boolean}
         */
        _this.hasUncheckedChildren = function(item) {
            return !!_this.find(item.items, function(subItem) {
                return !subItem.checked || _this.hasUncheckedChildren(subItem);
            });
        };
        /**
         * 指定节点是否半选状态，但不检查当前节点。即：既有被选中的子节点，也有未选中的子节点
         * @param item {Object} 起始节点
         * @return {boolean}
         */
        _this.hasSemiCheckedChildren = function(item) {
            return _this.hasCheckedChildren(item) && _this.hasUncheckedChildren(item);
        };
        /**
         * 当前节点是否半选状态，hasSemiCheckedChildren的别名
         * @param item {Object}
         * @returns {boolean}
         */
        _this.isSemiChecked = function(item) {
            return _this.hasSemiCheckedChildren(item);
        };
        /**
         * 更新item的父级节点，重新检查它们的checked和semiChecked状态
         * @param items
         * @param item
         * @private
         */
        _this._updateParents = function(items, item) {
            angular.forEach(items, function(subItem) {
                if(_this.hasChildren(subItem, item)) {
                    // 先要递归更新子级，否则中间节点的状态可能仍然处于选中状态，会影响当前节点的判断
                    _this._updateParents(subItem.items, item);
                    subItem.checked = _this.hasCheckedChildren(subItem);
                    subItem.semiChecked = _this.isSemiChecked(subItem);
                }
            });
        };
        _this.updateChecked = function(item) {
            _this._updateParents(_this.tree, item);
        };
        /**
         * 选中/反选指定节点
         * @param item {Object}
         * @param checked {boolean}
         * @private
         */
        _this._check = function(item, checked) {
            item.checked = checked;
            // 把当前节点的选中状态应用到所有下级
            angular.forEach(item.items, function(subItem) {
                _this._check(subItem, checked);
            });
            // 自动更新所有上级的状态
            _this._updateParents(_this.tree, item);
        };
        _this._find = function(items, item) {
            if (!items)
                return null;
            // 在子节点中查找
            for (var i = 0; i < items.length; ++i) {
                var subItem = items[i];
                // 如果找到了则直接返回
                if (_this.isSame(subItem, item))
                    return subItem;
                // 否则递归查找
                var subResult = _this._find(subItem.items, item);
                if (subResult)
                    return subResult;
            }
            return null;
        };
        /**
         * 查找指定的节点，会使用cbIsSame参数
         * @param item
         * @returns {Object}
         */
        _this.find = function(item) {
            return _this._find(_this.tree, item);
        };
        /**
         * parent及其子节点中有没有指定的subItem节点
         * @param parent {Object}
         * @param subItem {Object|Array}
         * @returns {boolean}
         */
        _this.hasChildren = function(parent, subItem) {
            var subItems = angular.isArray(subItem) ? subItem : [subItem];
            return !!_this.find(subItems, function(subItem) {
                return _this._find(parent.items, subItem);
            });
        };
        /**
         * 选中节点
         * @param item {Object}
         * @param checked {boolean}
         */
        _this.check = function(item, checked) {
            item = _this.find(item);
            _this._check(item, checked || angular.isUndefined(checked));
        };
        /**
         * 反选节点
         * @param item {Object}
         */
        _this.uncheck = function(item) {
            item = _this.find(item);
            _this._check(item, false);
        };
        /**
         * 切换节点的选中状态
         * @param item {Object}
         */
        _this.toggleCheck = function(item) {
            item = _this.find(item);
            _this._check(item, !item.checked);
        };
        /**
         * 指定节点是否被选中
         * @param item {Object}
         * @returns {boolean}
         */
        _this.isChecked = function(item) {
            item = _this.find(item);
            return item.checked;
        };
    }
    return TreeData;
});

